﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using Microsoft.Win32;
using NLog;

namespace SystemSettings
{
    public class IpHelper
    {
        private const int OpenExisting = 3;
        private const int FileAttributeNormal = 0x80;
        private const int InvalidHandleValue = -1;
        private const int IoctlNdisRebindAdapter = 1507374;
        private const int IoctlNdisGetAdapterNames = 1507386;
        private static readonly Logger Log = LogManager.GetCurrentClassLogger();

        [DllImport("Coredll.dll", EntryPoint = "CreateFile")]
        private static extern int CreateFile(
                string lpFileName,
                int dwDesiredAccess,
                int dwShareMode,
                int lpSecurityAttributes,
                int dwCreationDisposition,
                int dwFlagsAndAttributes,
                int hTemplateFile
            );

        [DllImport("Coredll.dll", EntryPoint = "DeviceIoControl")]
        private static extern int DeviceIoControl(
                int hDevice,
                int dwIoControlCode,
                string lpInBuffer,
                int nInBufferSize,
                string lpOutBuffer,
                int nOutBufferSize,
                int lpBytesReturned,
                int lpOverlapped
            );

        [DllImport("Coredll.dll", EntryPoint = "DeviceIoControl")]
        private static extern int DeviceIoControl2(
                int hDevice,
                int dwIoControlCode,
                string lpInBuffer,
                int nInBufferSize,
                string lpOutBuffer,
                int nOutBufferSize,
                ref int lpBytesReturned,
                int lpOverlapped
            );

        [DllImport("Coredll.dll", EntryPoint = "CloseHandle")]
        private static extern int CloseHandle(int hObject);

        /**/
        /// <summary>  
        /// 保存以太网卡IP地址信息的注册表节点  
        /// </summary>  
        private const string TcpIpRegKeyName = @"HKEY_LOCAL_MACHINE\Comm\{0}\Parms\TcpIp";

        /**/
        /// <summary>  
        /// IP地址注册表项名称  
        /// </summary>  
        private const string IpAddressItem = "IpAddress";

        /**/
        /// <summary>  
        /// 子网掩码的注册表项名称  
        /// </summary>  
        private const string SubnetMaskItem = "Subnetmask";

        /**/
        /// <summary>  
        /// 默认网关的注册表项名称  
        /// </summary>  
        private const string DefaultGatewayItem = "DefaultGateway";

        /**/
        /// <summary>  
        /// 以太网卡的设备文件名称  
        /// </summary>  
        private const string EtherCardFileName = "NDS0:";

        /**/

        /// <summary>  
        /// 以太网卡的名称  
        /// </summary>  
        private static List<string> _etherCardNames;

        /**/
        /// <summary>  
        /// 保存真实的以太网卡IP地址信息的注册表节点  
        /// </summary>  
        private static string _realTcpIpRegKeyName = string.Empty;

        private const string EnableDhcpName = "EnableDHCP";
        /**/
        /// <summary>  
        /// 在注册表中对IP信息进行修改后，禁用网卡然后重启网卡以应用修改  
        /// </summary>  
        public static bool ApplyIpAddress()
        {
            int hNdis = CreateFile(EtherCardFileName, 0, 0, 0, OpenExisting, FileAttributeNormal, InvalidHandleValue);
            if (hNdis == InvalidHandleValue)
            {
                return false;
            }

            GetEtherCardName();
            if (_etherCardNames == null || !_etherCardNames.Any()) return false;
            var ncn = _etherCardNames.FirstOrDefault();
            if (ncn == null) return false;
            // Send the device command.  
            if (DeviceIoControl(hNdis, IoctlNdisRebindAdapter, ncn, ncn.Length * 2 + 2, null, 0, 0, 0) == 0)
            {
                return false;
            }

            CloseHandle(hNdis);
            return true;
        }
        /// <summary>
        /// IP地址生效
        /// </summary>
        /// <param name="cardNo">网卡序号</param>
        /// <returns></returns>
        public static bool ApplyIpAddress(int cardNo)
        {
            int hNdis = CreateFile(EtherCardFileName, 0, 0, 0, OpenExisting, FileAttributeNormal, InvalidHandleValue);
            if (hNdis == InvalidHandleValue)
            {
                return false;
            }
            GetEtherCardName();
            if (_etherCardNames == null || !_etherCardNames.Any()) return false;
            if (cardNo > _etherCardNames.Count - 1) return false;
            var ncn = _etherCardNames[cardNo];
            if (ncn == null) return false;
            // Send the device command.  
            if (DeviceIoControl(hNdis, IoctlNdisRebindAdapter, ncn, ncn.Length * 2 + 2, null, 0, 0, 0) == 0)
            {
                return false;
            }

            CloseHandle(hNdis);
            return true;
        }
        /// <summary>
        /// ip地支生效
        /// </summary>
        /// <param name="cardName">网卡名称</param>
        /// <returns></returns>
        public static bool ApplyIpAddress(string cardName)
        {
            int hNdis = CreateFile(EtherCardFileName, 0, 0, 0, OpenExisting, FileAttributeNormal, InvalidHandleValue);
            if (hNdis == InvalidHandleValue)
            {
                return false;
            }
            GetEtherCardName();
            if (_etherCardNames == null || !_etherCardNames.Any()) return false;
            if (string.IsNullOrEmpty(cardName))
            {
                cardName = _etherCardNames.FirstOrDefault();
                if (cardName == null) return false;
            }

            // Send the device command.  
            if (DeviceIoControl(hNdis, IoctlNdisRebindAdapter, cardName, cardName.Length * 2 + 2, null, 0, 0, 0) == 0)
            {
                return false;
            }

            CloseHandle(hNdis);
            return true;
        }

        public static string GetGateWay()
        {
            return GetRegValue("", DefaultGatewayItem, "0.0.0.0");
        }

        public static string GetGateWay(int cardNo)
        {
            GetEtherCardName();
            if (_etherCardNames == null || !_etherCardNames.Any()) return string.Empty;
            if (cardNo > _etherCardNames.Count - 1) return string.Empty;
            var ncn = _etherCardNames[cardNo];
            return GetRegValue(ncn, DefaultGatewayItem, "0.0.0.0");
        }

        public static string GetGateWay(string cardName)
        {
            GetEtherCardName();
            if (_etherCardNames == null || !_etherCardNames.Any()) return string.Empty;
            if (string.IsNullOrEmpty(cardName))
            {
                cardName = _etherCardNames.FirstOrDefault();
                if (cardName == null) return string.Empty;
            }
            return GetRegValue(cardName, DefaultGatewayItem, "0.0.0.0");
        }

        ///
        /// 设置网关IP
        ///
        ///
        ///
        public static bool SetGateWay(string ip)
        {
            if (string.IsNullOrEmpty(ip))
                throw new ArgumentNullException("ip");

            return SetRegValue("", DefaultGatewayItem, ip);
        }
        /// <summary>
        /// 设置默认网关
        /// </summary>
        /// <param name="cardNo">网卡序号</param>
        /// <param name="ip"></param>
        /// <returns></returns>
        public static bool SetGateWay(int cardNo, string ip)
        {
            //if (string.IsNullOrEmpty(ip))
            //    throw new ArgumentNullException("ip");
            GetEtherCardName();
            if (_etherCardNames == null || !_etherCardNames.Any()) return false;
            if (cardNo > _etherCardNames.Count - 1) return false;
            var ncn = _etherCardNames[cardNo];
            return SetRegValue(ncn, DefaultGatewayItem, ip);
        }
        /// <summary>
        /// 设置默认网关
        /// </summary>
        /// <param name="cardName"></param>
        /// <param name="ip"></param>
        /// <returns></returns>
        public static bool SetGateWay(string cardName, string ip)
        {
            //if (string.IsNullOrEmpty(ip))
            //    throw new ArgumentNullException("ip");
            GetEtherCardName();
            if (_etherCardNames == null || !_etherCardNames.Any()) return false;
            if (string.IsNullOrEmpty(cardName))
            {
                cardName = _etherCardNames.FirstOrDefault();
                if (cardName == null) return false;
            }
            return SetRegValue(cardName, DefaultGatewayItem, ip);
        }
        /**/
        /// <summary>  
        /// 获取子网掩码  
        /// </summary>  
        /// <returns></returns>  
        public static string GetSubnetMask()
        {
            return GetRegValue("", SubnetMaskItem, "0.0.0.0");
        }
        /// <summary>
        /// 获取子网掩码
        /// </summary>
        /// <param name="cardNo"></param>
        /// <returns></returns>
        public static string GetSubnetMask(int cardNo)
        {
            GetEtherCardName();
            if (_etherCardNames == null || !_etherCardNames.Any()) return string.Empty;
            if (cardNo > _etherCardNames.Count - 1) return string.Empty;
            var ncn = _etherCardNames[cardNo];
            return GetRegValue(ncn, SubnetMaskItem, "0.0.0.0");
        }
        /// <summary>
        /// 获取子网掩码
        /// </summary>
        /// <param name="cardName"></param>
        /// <returns></returns>
        public static string GetSubnetMask(string cardName)
        {
            GetEtherCardName();
            if (_etherCardNames == null || !_etherCardNames.Any()) return string.Empty;
            if (string.IsNullOrEmpty(cardName))
            {
                cardName = _etherCardNames.FirstOrDefault();
                if (cardName == null) return string.Empty;
            }
            return GetRegValue(cardName, SubnetMaskItem, "0.0.0.0");
        }

        /**/
        /// <summary>  
        /// 设置子网掩码  
        /// </summary>  
        /// <param name="subnetMask"></param>  
        /// <returns></returns>  
        public static bool SetSubnetMask(string subnetMask)
        {
            if (string.IsNullOrEmpty(subnetMask))
            {
                throw new ArgumentNullException(subnetMask);
            }

            return SetRegValue("", SubnetMaskItem, subnetMask);
        }
        /// <summary>
        /// 设置子网掩码
        /// </summary>
        /// <param name="cardNo"></param>
        /// <param name="subnetMask"></param>
        /// <returns></returns>
        public static bool SetSubnetMask(int cardNo, string subnetMask)
        {
            if (string.IsNullOrEmpty(subnetMask))
            {
                throw new ArgumentNullException(subnetMask);
            }
            GetEtherCardName();
            if (_etherCardNames == null || !_etherCardNames.Any()) return false;
            if (cardNo > _etherCardNames.Count - 1) return false;
            var ncn = _etherCardNames[cardNo];
            return SetRegValue(ncn, SubnetMaskItem, subnetMask);
        }
        /// <summary>
        /// 设置子网掩码
        /// </summary>
        /// <param name="cardName"></param>
        /// <param name="subnetMask"></param>
        /// <returns></returns>
        public static bool SetSubnetMask(string cardName, string subnetMask)
        {
            if (string.IsNullOrEmpty(subnetMask))
            {
                throw new ArgumentNullException(subnetMask);
            }
            GetEtherCardName();
            if (_etherCardNames == null || !_etherCardNames.Any()) return false;
            if (string.IsNullOrEmpty(cardName))
            {
                cardName = _etherCardNames.FirstOrDefault();
                if (cardName == null) return false;
            }
            return SetRegValue(cardName, SubnetMaskItem, subnetMask);
        }
        /**/
        /// <summary>  
        /// 获取IP地址  
        /// </summary>  
        /// <returns></returns>  
        public static string GetIpAddress()
        {
            return GetRegValue("", IpAddressItem, "0.0.0.0");
        }
        public static string GetIpAddress(int cardNo)
        {
            GetEtherCardName();
            if (_etherCardNames == null || !_etherCardNames.Any()) return string.Empty;
            if (cardNo > _etherCardNames.Count - 1) return string.Empty;
            var ncn = _etherCardNames[cardNo];
            return GetRegValue(ncn, IpAddressItem, "0.0.0.0");
        }
        public static string GetIpAddress(string cardName)
        {
            GetEtherCardName();
            if (_etherCardNames == null || !_etherCardNames.Any()) return string.Empty;
            if (string.IsNullOrEmpty(cardName))
            {
                cardName = _etherCardNames.FirstOrDefault();
                if (cardName == null) return string.Empty;
            }
            return GetRegValue(cardName, IpAddressItem, "0.0.0.0");
        }

        /**/
        /// <summary>  
        /// 设置Ip地址  
        /// </summary>  
        /// <param name="ip"></param>  
        public static bool SetIpAddress(string ip)
        {
            if (string.IsNullOrEmpty(ip))
                throw new ArgumentNullException("ip");

            return SetRegValue("", IpAddressItem, ip);
        }
        public static bool SetIpAddress(int cardNo, string ip)
        {
            if (string.IsNullOrEmpty(ip))
                throw new ArgumentNullException("ip");
            GetEtherCardName();
            if (_etherCardNames == null || !_etherCardNames.Any()) return false;
            if (cardNo > _etherCardNames.Count - 1) return false;
            var ncn = _etherCardNames[cardNo];
            return SetRegValue(ncn, IpAddressItem, ip);
        }
        public static bool SetIpAddress(string cardName, string ip)
        {
            if (string.IsNullOrEmpty(ip))
                throw new ArgumentNullException("ip");
            GetEtherCardName();
            if (_etherCardNames == null || !_etherCardNames.Any()) return false;
            if (string.IsNullOrEmpty(cardName))
            {
                cardName = _etherCardNames.FirstOrDefault();
                if (cardName == null) return false;
            }
            return SetRegValue(cardName, IpAddressItem, ip);
        }

        public static string GetDhcpStatus()
        {
            return GetRegValue("", EnableDhcpName, "0");
        }
        public static string GetDhcpStatus(int cardNo)
        {
            GetEtherCardName();
            if (_etherCardNames == null || !_etherCardNames.Any()) return string.Empty;
            if (cardNo > _etherCardNames.Count - 1) return string.Empty;
            var ncn = _etherCardNames[cardNo];
            return GetRegValue(ncn, EnableDhcpName, "0");
        }
        public static string GetDhcpStatus(string cardName)
        {
            GetEtherCardName();
            if (_etherCardNames == null || !_etherCardNames.Any()) return string.Empty;
            if (string.IsNullOrEmpty(cardName))
            {
                cardName = _etherCardNames.FirstOrDefault();
                if (cardName == null) return string.Empty;
            }
            return GetRegValue(cardName, EnableDhcpName, "0");
        }

        public static bool SetDhcpStatus(bool enable)
        {

            return SetRegValue("", EnableDhcpName, enable ? 1 : 0);
        }
        public static bool SetDhcpStatus(int cardNo, bool enable)
        {
            GetEtherCardName();
            if (_etherCardNames == null || !_etherCardNames.Any()) return false;
            if (cardNo > _etherCardNames.Count - 1) return false;
            var ncn = _etherCardNames[cardNo];
            return SetRegValue(ncn, EnableDhcpName, enable ? 1 : 0);
        }
        public static bool SetDhcpStatus(string cardName, bool enable)
        {
            GetEtherCardName();
            if (_etherCardNames == null || !_etherCardNames.Any()) return false;
            if (string.IsNullOrEmpty(EnableDhcpName))
            {
                cardName = _etherCardNames.FirstOrDefault();
                if (cardName == null) return false;
            }
            return SetRegValue(cardName, EnableDhcpName, enable ? 1 : 0);
        }


        /**/
        /// <summary>  
        /// 获得网卡的名称  
        /// </summary>  
        /// <returns></returns>  
        private static void GetEtherCardName()
        {
            if (_etherCardNames != null) return;
            var names = new string(' ', 255);
            int bytes = 0;
            _etherCardNames = new List<string>();
            int fileHandle = CreateFile(EtherCardFileName, 0, 0, 0, OpenExisting, FileAttributeNormal, InvalidHandleValue);
            if (fileHandle == InvalidHandleValue)
            {
                return;
            }

            if (DeviceIoControl2(fileHandle, IoctlNdisGetAdapterNames, null, 0, names, 255, ref bytes, 0) == 0)
            {
                return;
            }

            var cns = names.Split('\0');
            foreach (var str in cns)
            {
                if (string.IsNullOrEmpty(str.Trim())) continue;
                if (!str.Contains("\\")) continue;
                _etherCardNames.Add(str.Trim());
            }
        }


        /**/
        /// <summary>  
        /// 获取注删表项的值  
        /// </summary>  
        private static string GetRegValue(string cardName, string regItemName, string defaultValue)
        {
            if (_etherCardNames == null || !_etherCardNames.Any())
            {
                GetEtherCardName();
            }
            if (_etherCardNames != null)
            {
                if (string.IsNullOrEmpty(cardName))
                {
                    cardName = _etherCardNames.FirstOrDefault();
                    if (cardName == null) return string.Empty;
                }
                _realTcpIpRegKeyName = string.Format(TcpIpRegKeyName, cardName);
            }
            else
            {
                return string.Empty;
            }
            try
            {
                object value = Registry.GetValue(_realTcpIpRegKeyName, regItemName, defaultValue);
                if (value != null)
                {
                    if (value.GetType() == typeof(string[]))
                    {
                        return ((string[])value)[0];
                    }
                    return value.ToString();
                }
            }
            catch (Exception e)
            {
                Log.Error("获取注册表值 {0} 失败", e, _realTcpIpRegKeyName);
            }

            return defaultValue;
        }

        /**/
        /// <summary>  
        /// 设置注册表项的值  
        /// </summary>  
        private static bool SetRegValue(string cardName, string regItemName, object value)
        {
            if (_etherCardNames == null || !_etherCardNames.Any())
            {
                GetEtherCardName();
            }

            if (_etherCardNames != null)
            {
                if (string.IsNullOrEmpty(cardName))
                {
                    cardName = _etherCardNames.FirstOrDefault();
                    if (cardName == null) return false;
                }

                _realTcpIpRegKeyName = string.Format(TcpIpRegKeyName, cardName);
            }
            else
            {
                return false;
            }
            try
            {
                Registry.SetValue(_realTcpIpRegKeyName, regItemName, value);
                return true;
            }
            catch (Exception e)
            {
                Log.Error("设置注册表值 {0} 失败", e, _realTcpIpRegKeyName);
                return false;
            }
        }
    }
}
